package com.yf.course.websocket.server;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import com.yf.ability.redis.service.RedisService;
import com.yf.ability.websocket.CustomSpringConfigurator;
import com.yf.course.modules.course.dto.ext.CourseLearnResultExtDTO;
import com.yf.course.modules.course.entity.CourseFileLearn;
import com.yf.course.modules.course.entity.CourseRefFile;
import com.yf.course.modules.course.service.CourseFileLearnService;
import com.yf.course.modules.course.service.CourseRefFileService;
import com.yf.course.websocket.dto.StudyRecordDTO;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;

/**
 * @author bool
 */
@Log4j2
@Component
@ServerEndpoint(value = "/api/socket/read/{userId}/{courseId}/{fileId}", configurator = CustomSpringConfigurator.class)
public class ReadEndpoint {

    /**
     * 至少60秒才记录
     */
    public static final Long MIN_TIME = 60L;

    /**
     * Redis
     */
    @Autowired
    private RedisService redisService;
    /**
     * 课程相关
     */
    @Autowired
    private CourseFileLearnService courseFileLearnService;

    @Autowired
    private CourseRefFileService courseRefFileService;



    /**
     * 连接成功
     * @param userId
     * @param fileId
     */
    @OnOpen
    public void onOpen(@PathParam("userId") String userId,
                       @PathParam("courseId") String courseId,
                       @PathParam("fileId") String fileId) {
        log.info("++++++++++阅读socket开启，userId:{},courseId:{},fileId:{}", userId, courseId, fileId);

        // 初始化学习记录
        CourseFileLearn learn = courseFileLearnService.findOne(userId, courseId, fileId);

        // 文件需要时长
        CourseRefFile refFile = courseRefFileService.findOne(courseId, fileId);

        // 查找课件的总时长，已学习分钟数+残留缓存
        String key = this.cacheKey(userId, courseId, fileId);

        // 从数据库中提取阅读进度
        JSONObject obj = redisService.getJson(key);
        StudyRecordDTO cache;

        // 为空时进行初始化
        if(obj != null){
            cache = obj.toJavaObject(StudyRecordDTO.class);
        }else{
            cache = new StudyRecordDTO();
        }

        // 剩余阅读秒数
        long leftSec = refFile.getNeedLearn() - learn.getLearnSec();

        // 保存解锁缓存
        String unlock = this.unlockKey(userId, courseId);
        String unlockFile = redisService.getString(unlock);
        if(StringUtils.isNotBlank(unlockFile)){
            cache.setUnlockFile(unlockFile);
        }

        //将当前时间放入缓存中
        cache.setCreateTime(System.currentTimeMillis());
        cache.setLeftSec(leftSec);
        cache.setLearnSec(learn.getLearnSec());
        cache.setAll(false);
        cache.setStopped(false);
        cache.setStopMsg(null);
        cache.setCurrent(learn.getLearnSec() >= refFile.getNeedLearn());
        redisService.set(key, JSON.toJSONString(cache));
    }

    /**
     * 连接关闭时
     * @param userId
     * @param fileId
     */
    @OnClose
    public void onClose(@PathParam("userId") String userId,
                        @PathParam("courseId") String courseId,
                        @PathParam("fileId") String fileId) {

        log.info("++++++++++阅读socket关闭，userId:{},courseId:{},fileId:{}", userId, courseId, fileId);

        String key = this.cacheKey(userId, courseId, fileId);
        // 获取缓存
        StudyRecordDTO cache = this.getCache(userId, courseId ,fileId);

        if(cache == null){
            return;
        }

        // 获得累计阅读时间
        long sec = this.getSec(cache);

        // 大于1分钟则存库
        if(sec >= 0){
            // 更新数据库进度
            courseFileLearnService.incr(userId, courseId, fileId, sec);
        }

        // 保存缓存
        redisService.set(key, JSON.toJSONString(cache));
    }


    /**
     * 收到主动轮询消息
     * @param text
     * @throws IOException
     */
    @OnMessage
    public void onMsg(Session session, String text, @PathParam("userId") String userId,
                      @PathParam("courseId") String courseId,
                      @PathParam("fileId") String fileId) throws IOException {


        log.info("++++++++++收到ping信息{}，userId:{},courseId:{},fileId:{}", text, userId, courseId, fileId);

        String key = this.cacheKey(userId, courseId, fileId);

        // 获取缓存
        StudyRecordDTO cache = this.getCache(userId, courseId, fileId);

        if(cache == null){
            return;
        }

        // 已读秒数+残值
        long read = this.getSec(cache);

        // 30秒以上入库一次
        if(read > 30){
            CourseLearnResultExtDTO resp = courseFileLearnService.incr(userId, courseId, fileId, read);

            if(resp!=null) {

                // 阅读时间超限
                if(resp.getStopped()!=null && resp.getStopped()){
                    cache.setStopped(true);
                    cache.setStopMsg(resp.getStopMsg());
                }

                cache.setCurrent(resp.getCurrent());
                cache.setAll(resp.getAll());

                // 返回剩余的描述
                cache.setLeftSec(resp.getLeftSec());
                cache.setLearnSec(resp.getLearnSec());

                if(StringUtils.isNotBlank(resp.getUnlockFile())){

                    // 保存解锁缓存
                    String unlock = this.unlockKey(userId, courseId);
                    redisService.set(unlock, resp.getUnlockFile());

                    // 解锁的课件
                    cache.setUnlockFile(resp.getUnlockFile());
                }
            }

            // 更新数据
            cache.setCreateTime(System.currentTimeMillis());
        }



        // 更新数据
        String json = JSON.toJSONString(cache);

        // 记录缓存
        redisService.set(key, json);

        // 发送消息到前端
        session.getBasicRemote().sendText(json);
    }

    /**
     * 配置错误信息处理
     * @param session
     * @param t
     */
    @OnError
    public void onError(Session session, Throwable t) {
        log.info("socket连接已断开...");
    }


    /**
     * 获得缓存秘钥
     * @param userId
     * @param fileId
     * @return
     */
    private String cacheKey(String userId, String courseId, String fileId){
        return "file:cache:"+userId+":"+courseId+":"+fileId;
    }

    /**
     * 构建缓存KEY
     * @param userId
     * @param courseId
     * @return
     */
    private String unlockKey(String userId, String courseId){
        return "file:unlock:"+userId+":"+courseId;
    }



    /**
     * 获取阅读缓存
     * @param userId
     * @param fileId
     * @return
     */
    private StudyRecordDTO getCache(String userId, String courseId, String fileId){

        // 获取阅读缓存
        String key = this.cacheKey(userId, courseId, fileId);

        // 从数据库中提取阅读进度
        JSONObject obj = redisService.getJson(key);
        if(obj != null) {
            //获取阅读缓存
            return obj.toJavaObject(StudyRecordDTO.class);
        }

        return null;
    }

    /**
     * 获取阅读持续时间
     * @param cache
     * @return
     */
    private long getSec(StudyRecordDTO cache){

        // 持续时间秒数
        long sec =  (System.currentTimeMillis() - cache.getCreateTime()) / 1000;
        return sec;
    }
}
